package com.atom.test.opengl

import android.annotation.SuppressLint
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.PointF
import android.opengl.GLES30
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SurfaceHolder
import android.view.SurfaceView
import androidx.appcompat.app.AppCompatActivity
import com.atom.module.lib.opengles.GLModule
import com.atom.module.lib.opengles.draw.Gl2dMesh
import com.atom.module.lib.opengles.draw.GlCircle
import com.atom.module.lib.opengles.egl.EGLHelper
import com.atom.module.lib.opengles.egl.EGLWrapper
import com.atom.module.lib.opengles.ext.*
import com.atom.module.lib.opengles.shader.GlScene
import com.atom.module.lib.opengles.shader.GlSimpleProgram
import com.atom.module.logger.Logger
import com.atom.test.opengl.gesture.*
import com.atom.test.opengl.utils.MatrixState
import java.util.*

class ModelMatrixActivity : AppCompatActivity(), GestureListener {

    private lateinit var surfaceView: SurfaceView
    private lateinit var wrapper: EGLWrapper
    private var flatProgram: GlSimpleProgram? = null

    private val scene = GlScene()
    private val drawable = Gl2dMesh().apply {
        this.setPoints(
            listOf(
                PointF(0F, 0F),//0
                PointF(0F, 1F),//1
                PointF(1F, 0F),//2
                PointF(0F, -1F),//3
                PointF(-1F, 0F),//4
                PointF(0.9F, 0.7F),//5
                PointF(0.7F, 0.9F),//6
                PointF(-0.9F, -0.7F),//7
                PointF(-0.7F, -0.9F),//8
                PointF(0.9F, -0.7F),//9
                PointF(0.7F, -0.9F),//10
                PointF(-0.9F, 0.7F),//11
                PointF(-0.7F, 0.9F)//12
            )
        )
    }

    protected var panRecognizer = PanRecognizer()
    protected var pinchRecognizer = PinchRecognizer()
    protected var rotationRecognizer = RotationRecognizer()
    protected var allRecognizers = Arrays.asList(
        panRecognizer, pinchRecognizer, rotationRecognizer
    )

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setTitle("ModelMatrixActivity")
        surfaceView = SurfaceView(this)
        surfaceView.setZOrderOnTop(true)
        surfaceView.holder.setFormat(PixelFormat.RGBA_8888)
        surfaceView.holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                Log.e("SHAPES", "CREATED." + Thread.currentThread().name)
                onSurfaceCreated(holder)
            }

            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int
            ) {

            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {
                onSurfaceDestroyed()
            }
        })
        surfaceView.setOnTouchListener { v, event ->
            var handled = false
            for (idx in 0 until allRecognizers.size) {
                handled = handled or allRecognizers[idx].onTouchEvent(event)
            }
            handled
        }
        for (entry in allRecognizers) {
            entry.addListener(this)
        }
        setContentView(surfaceView)
    }

    private fun onSurfaceCreated(holder: SurfaceHolder) {
        wrapper = EGLHelper.initDisplay()
        wrapper.createGLESWithSurface(surface = holder.surface!!)
        flatProgram = GlSimpleProgram()
    }

    private fun onSurfaceDestroyed() {
        flatProgram?.release()
        flatProgram = null
        wrapper.release()
    }

    private fun draw() {
        Log.w("SHAPES", "drawing.")
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
        // Draw the circle.
        flatProgram!!.setColor(Color.RED)
        scene.draw(flatProgram!!, drawable)
        // Publish.
        wrapper.swapBuffers()
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
            Log.e(GLModule.TAG, "Model Matrix ${drawable.modelMatrix.print()}")
        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
            Logger.e(MatrixState.printMatrix(drawable.modelMatrix))
        }
        return super.onKeyDown(keyCode, event)
    }

    override fun gestureStateChanged(event: MotionEvent, recognizer: GestureRecognizer) {
        if (recognizer === panRecognizer) {
            Logger.e(
                "panRecognizer > \n" +
                        "panX = ${recognizer.panX()} \n " +
                        "panY = ${recognizer.panY()} \n "
            )
            drawable.modelMatrix.translateX(recognizer.translationX/drawable.viewportWidth)
            drawable.modelMatrix.translateY(-recognizer.translationY/drawable.viewportHeight)
        } else if (recognizer === pinchRecognizer) {
            val scale = recognizer.scale()
            Logger.e(
                "pinchRecognizer > \n" +
                        "scale = ${scale} \n "
            )
            drawable.modelMatrix.scaleZ(scale)
            drawable.modelMatrix.scaleX(scale)
            drawable.modelMatrix.scaleY(scale)
        } else if (recognizer === rotationRecognizer) {
            val rotation = recognizer.rotation()
            Logger.e(
                "rotationRecognizer > \n" +
                        "rotation = ${rotation} \n "
            )
            drawable.modelMatrix.rotateZ(rotation)
        }
        draw()
    }

    override fun onDestroy() {
        onSurfaceDestroyed()
        super.onDestroy()
    }
}